package sim;
import java.util.Random;



public class AI {
	private final static Random random = new Random();
	private final static double reproductionAreaDegreeOfMutation=200;
	private static final double reproductionCost = 1;
	private static final double fearValue = 200;
	//private final static double mutationRateDegreeOfMutation = 10;
	private static final double BLOB_FACTOR = 1;
	private static final double FOOD_FACTOR = 1;

	private int numberOfOffspring;
	private double mutationRate;
	private double reproductionArea;
	
	
	public AI(double reproductionArea, int numberOfOffspring, double mutationRate)
	{
		this.reproductionArea = reproductionArea;
		this.mutationRate = mutationRate;
		this.numberOfOffspring = numberOfOffspring;
	}
	
	public AI(AI parentAI) 
	{
		numberOfOffspring = parentAI.numberOfOffspring;
		mutationRate = parentAI.mutationRate;
		reproductionArea = mutate(parentAI.getReproductionArea(), reproductionAreaDegreeOfMutation);
	}

	private double mutate(double aiValue, double degreeOfMutation) 
	{
		if(random.nextDouble()<mutationRate)
		{
			//Number between -1 and 1
			double scaleFactor = (2*random.nextDouble()-1);

			//Number between -degreeOfMutation and degreeOfMutation
			double mutationAmount = scaleFactor * degreeOfMutation;
			
			//Prevent negative numbers
			return Math.max(aiValue + mutationAmount,0);
		}
		else
		{
			return aiValue;
		}		
	}

	public Blob[] reproduce(Blob blob)
	{
		//update AI for child blobs, possibly mutate
		AI ai = new AI(blob.getAI());
		//create new child blobs and send in different directions, by dividing up a circle into the same number of slices as there are blobs
		Blob[] newBlobs = new Blob[blob.getAI().getNumberOfOffspring()];
		double slice = Vec2.divideCircleIntoAngleSlices(blob.getAI().getNumberOfOffspring());
		
		double reducedArea = blob.getArea() - (reproductionCost * (blob.getAI().getNumberOfOffspring() - 1));
		
		
		for(int i=0;i<blob.getAI().getNumberOfOffspring();i++)
		{
			Vec2 offset = Vec2.specifiedDirectionVec2(blob.getRadius(),i*slice);
			//Vec2 velocity = Vec2.Add((Vec2.specifiedDirectionVec2(100,i*slice)),(Vec2.randomSliceAngleVector(blob.getAI().getNumberOfOffspring(),100))); //fix magnitude?
			newBlobs[i] = new Blob(blob.getPosition().Add(offset), reducedArea/blob.getAI().getNumberOfOffspring(), ai);
			//newBlobs[i].move(velocity);
		}
		return newBlobs;				
	} 
	
	public double getReproductionArea() {
		return reproductionArea;
	}
	

	public int getNumberOfOffspring() 
	{
		return numberOfOffspring;
	}

	public boolean shouldReproduce(Blob blob) 
	{
		return blob.getArea() >= reproductionArea;
	}
	
	private double blobPreyValue(Blob blob, Blob otherBlob)
	{
		return blob.getArea()-otherBlob.getArea()-fearValue;
	}
	
	public Vec2 desiredBlobVec2(Blob blob, Blob otherBlob)
	{
		double distance =  TorusMath.instance.distance(blob.getPosition(), blob.getRadius(), otherBlob.getPosition(), otherBlob.getRadius());
		distance = Math.max(distance,0);
		double bias = .5;
		
		double weight = BLOB_FACTOR/(distance+bias);
		
		Vec2 direction = TorusMath.instance.pointDifference((blob.getPosition()), otherBlob.getPosition()).Unit();
		return direction.Scale(blobPreyValue(blob, otherBlob)*weight);
//		return direction.Scale(-otherBlob.getArea()*weight);
	}
	public Vec2 desiredFoodVec2(Blob blob, Food food)
	{
		double distance =  TorusMath.instance.distance(blob.getPosition(), blob.getRadius(), food.getPosition(), food.getRadius());
		distance = Math.max(distance,0);
		double bias = .5;
		double weight = FOOD_FACTOR/(distance+bias);
		Vec2 direction = TorusMath.instance.pointDifference((blob.getPosition()), food.getPosition()).Unit();
		return direction.Scale(food.getArea()*weight);
	}
	
}
